﻿using Engine;
using Engine.Graphics;

namespace Game
{
    public abstract class FoodItemBlock : Block
    {
        public Texture2D m_texture;

        public string texture;

        public string ClassName;

        public int Index;

        public FoodType m_foodtype;

        public float SicknessProbability;

        public int RotPeriod;

        public float NutritionalValue;

        public int Placementvalue;

        public bool IsPlaceables;

        public string Displayname;

        public int m_rottenValue;

        public Color? DrawColor;

        public string ModelPath;

        public string MeshName;

        public bool Fruit;

        public BlockMesh m_standaloneBlockMesh = new BlockMesh();

        public BoundingBox[] m_collisinbox = new BoundingBox[1];

        public FoodItemBlock(int index, string textureName, string classname, FoodType foodtype, float sicknessProbability, int rotPeriod, float nutritionalValue, int placementvalue, bool isPlaceable, string displayname, int rottenvalue)
        {
            m_rottenValue = rottenvalue;
            Displayname = displayname;
            IsPlaceables = isPlaceable;
            Placementvalue = placementvalue;
            NutritionalValue = nutritionalValue;
            RotPeriod = rotPeriod;
            SicknessProbability = sicknessProbability;
            m_foodtype = foodtype;
            Index = index;
            ClassName = classname;
            texture = textureName;
            DefaultDisplayName = Displayname;
            DefaultDescription = string.Format("{0},一种可口的食物，属于{1}，可以存放3天。", Displayname, GetFoodType(m_foodtype), RotPeriod / 10);
            FoodType = m_foodtype;
            DefaultNutritionalValue = NutritionalValue;
            DefaultRotPeriod = RotPeriod;
            Behaviors = "RotBlockBehavior";
            CraftingId = ClassName.ToLower();
            DefaultSicknessProbability = sicknessProbability;
            DefaultIconViewOffset = new Vector3(0f, 0f, 1f);
            DefaultCategory = "Food";
            DisplayOrder = 300;
            DefaultCreativeData = 0;
            IsPlaceable = IsPlaceables;
            IsPlacementTransparent = true;
            IsTransparent = true;
            FirstPersonScale = 0.4f;
            FirstPersonOffset = new Vector3(0.4f, -0.5f, -0.6f);
            FirstPersonRotation = new Vector3(0f, 0f, 0f);
            InHandScale = 0.3f;
            InHandOffset = new Vector3(0f, 0.12f, 0f);
            InHandRotation = new Vector3(100f, 0f, 0f);
            IsCollidable = false;
        }

        public FoodItemBlock(int index, string textureName, string classname, FoodType foodtype, float sicknessProbability, int rotPeriod, float nutritionalValue, int placementvalue, bool isPlaceable, string displayname, int rottenvalue, Color color)
        {
            DrawColor = color;
            m_rottenValue = rottenvalue;
            Displayname = displayname;
            IsPlaceables = isPlaceable;
            Placementvalue = placementvalue;
            NutritionalValue = nutritionalValue;
            RotPeriod = rotPeriod;
            SicknessProbability = sicknessProbability;
            m_foodtype = foodtype;
            Index = index;
            ClassName = classname;
            texture = textureName;
            DefaultDisplayName = Displayname;
            DefaultDescription = string.Format("{0},一种可口的食物，属于{1}，可以存放3天。", Displayname, GetFoodType(m_foodtype), RotPeriod / 10);
            FoodType = m_foodtype;
            DefaultNutritionalValue = NutritionalValue;
            DefaultRotPeriod = RotPeriod;
            Behaviors = "RotBlockBehavior";
            CraftingId = ClassName.ToLower();
            DefaultSicknessProbability = sicknessProbability;
            DefaultIconViewOffset = new Vector3(0f, 0f, 1f);
            DefaultCategory = "Food";
            DisplayOrder = 300;
            DefaultCreativeData = 0;
            IsPlaceable = IsPlaceables;
            IsPlacementTransparent = true;
            IsTransparent = true;
            FirstPersonScale = 0.4f;
            FirstPersonOffset = new Vector3(0.4f, -0.5f, -0.6f);
            FirstPersonRotation = new Vector3(0f, 0f, 0f);
            InHandScale = 0.3f;
            InHandOffset = new Vector3(0f, 0.12f, 0f);
            InHandRotation = new Vector3(100f, 0f, 0f);
            IsCollidable = false;
        }

        public FoodItemBlock(int index, string textureName, string classname, FoodType foodtype, float sicknessProbability, int rotPeriod, float nutritionalValue, int placementvalue, bool isPlaceable, string displayname, int rottenvalue, Color color, string modelpath, string meshname)
        {
            DefaultDropContent = index;
            MeshName = meshname;
            ModelPath = modelpath;
            DrawColor = color;
            m_rottenValue = rottenvalue;
            Displayname = displayname;
            IsPlaceables = isPlaceable;
            Placementvalue = placementvalue;
            NutritionalValue = nutritionalValue;
            RotPeriod = rotPeriod;
            SicknessProbability = sicknessProbability;
            m_foodtype = foodtype;
            Index = index;
            ClassName = classname;
            texture = textureName;
            DefaultDisplayName = Displayname;
            DefaultDescription = string.Format("{0},一种可口的食物，属于{1}，可以存放3天。", Displayname, GetFoodType(m_foodtype), RotPeriod / 10);
            FoodType = m_foodtype;
            DefaultNutritionalValue = NutritionalValue;
            DefaultRotPeriod = RotPeriod;
            Behaviors = "RotBlockBehavior";
            CraftingId = ClassName.ToLower();
            DefaultSicknessProbability = sicknessProbability;
            DefaultIconViewOffset = new Vector3(0f, 0f, 1f);
            DefaultCategory = "Food";
            DisplayOrder = 300;
            DefaultCreativeData = 0;
            IsPlaceable = IsPlaceables;
            IsPlacementTransparent = false;
            IsTransparent = true;
            FirstPersonScale = 0.4f;
            FirstPersonOffset = new Vector3(0.4f, -0.5f, -0.6f);
            FirstPersonRotation = new Vector3(0f, 0f, 0f);
            InHandScale = 0.3f;
            InHandOffset = new Vector3(0f, 0.12f, 0f);
            InHandRotation = new Vector3(100f, 0f, 0f);
            IsCollidable = true;
        }

        public FoodItemBlock(int index, string textureName, string classname, FoodType foodtype, float sicknessProbability, int rotPeriod, float nutritionalValue, int placementvalue, bool isPlaceable, string displayname, int rottenvalue, bool fruits)
        {
            Fruit = fruits;
            m_rottenValue = rottenvalue;
            Displayname = displayname;
            IsPlaceables = isPlaceable;
            Placementvalue = placementvalue;
            NutritionalValue = nutritionalValue;
            RotPeriod = rotPeriod;
            SicknessProbability = sicknessProbability;
            m_foodtype = foodtype;
            Index = index;
            ClassName = classname;
            texture = textureName;
            DefaultDisplayName = Displayname;
            DefaultDescription = string.Format("{0},一种可口的食物，属于{1}，可以存放3天。", Displayname, GetFoodType(m_foodtype), RotPeriod / 10);
            FoodType = m_foodtype;
            DefaultNutritionalValue = NutritionalValue;
            DefaultRotPeriod = RotPeriod;
            Behaviors = "RotBlockBehavior";
            CraftingId = ClassName.ToLower();
            DefaultSicknessProbability = sicknessProbability;
            DefaultIconViewOffset = new Vector3(0f, 0f, 1f);
            DefaultCategory = "Food";
            DisplayOrder = 300;
            DefaultCreativeData = 0;
            IsPlaceable = IsPlaceables;
            IsPlacementTransparent = true;
            IsTransparent = true;
            FirstPersonScale = 0.4f;
            FirstPersonOffset = new Vector3(0.4f, -0.5f, -0.6f);
            FirstPersonRotation = new Vector3(0f, 0f, 0f);
            InHandScale = 0.3f;
            InHandOffset = new Vector3(0f, 0.12f, 0f);
            InHandRotation = new Vector3(100f, 0f, 0f);
            IsCollidable = false;
            DestructionDebrisScale = 1f;
        }

        public override void Initialize()
        {
            base.Initialize();
            m_texture = ContentManager.Get<Texture2D>(texture);
            if (!string.IsNullOrEmpty(ModelPath))
            {
                Model model = ContentManager.Get<Model>(ModelPath);
                Matrix boneAbsoluteTransform = BlockMesh.GetBoneAbsoluteTransform(model.FindMesh(MeshName).ParentBone);
                m_standaloneBlockMesh.AppendModelMeshPart(model.FindMesh(MeshName).MeshParts[0], boneAbsoluteTransform * Matrix.CreateTranslation(0.5f, 0f, 0.5f) * Matrix.CreateScale(1f), makeEmissive: false, flipWindingOrder: false, doubleSided: true, flipNormals: false, Color.White);
                m_collisinbox[0] = m_standaloneBlockMesh.CalculateBoundingBox();
            }
        }

        public override BlockDebrisParticleSystem CreateDebrisParticleSystem(SubsystemTerrain subsystemTerrain, Vector3 position, int value, float strength)
        {
            m_texture = ContentManager.Get<Texture2D>(texture);
            Color color = BlockColorsMap.GrassColorsMap.Lookup(subsystemTerrain.Terrain, Terrain.ToCell(position.X), Terrain.ToCell(position.Y), Terrain.ToCell(position.Z));
            return new BlockDebrisParticleSystem(subsystemTerrain, position, strength, DestructionDebrisScale, color, GetFaceTextureSlot(4, value));
        }

        public override int GetDamageDestructionValue(int value)
        {
            return m_rottenValue;
        }

        public string GetFoodType(FoodType foodtype)
        {
            switch (foodtype)
            {
                case FoodType.Bread:
                    return "谷类";
                case FoodType.Fish:
                    return "鱼肉类";
                case FoodType.Grass:
                    return "蔬菜类";
                case FoodType.Meat:
                    return "肉类";
                case FoodType.None:
                    return "零食";
                case FoodType.Fruit:
                    return "水果";
                default:
                    return string.Empty;
            }
        }


        public override int GetTextureSlotCount(int value)
        {
            return 1;
        }

        public override int GetFaceTextureSlot(int face, int value)
        {
            if (face == -1)
            {
                return 0;
            }

            return 2;
        }

        public override void GenerateTerrainVertices(BlockGeometryGenerator generator, TerrainGeometry geometry, int value, int x, int y, int z)
        {
            if (Fruit)
            {
                generator.GenerateCrossfaceVertices(this, value, x, y, z, Color.White, GetFaceTextureSlot(1, value), geometry.GetGeometry(m_texture).SubsetAlphaTest);
            }
            else if (!string.IsNullOrEmpty(ModelPath))
            {
                generator.GenerateShadedMeshVertices(this, x, y, z, m_standaloneBlockMesh, Color.White, null, null, geometry.GetGeometry(m_texture).SubsetOpaque);
            }
        }

        public override BoundingBox[] GetCustomCollisionBoxes(SubsystemTerrain terrain, int value)
        {
            if (!string.IsNullOrEmpty(ModelPath))
            {
                return m_collisinbox;
            }

            return base.GetCustomCollisionBoxes(terrain, value);
        }

        public override void DrawBlock(PrimitivesRenderer3D primitivesRenderer, int value, Color color, float size, ref Matrix matrix, DrawBlockEnvironmentData environmentData)
        {
            if (!string.IsNullOrEmpty(ModelPath))
            {
                m_texture = ContentManager.Get<Texture2D>(texture);
                BlocksManager.DrawMeshBlock(primitivesRenderer, m_standaloneBlockMesh, m_texture, color, 1f * size, ref matrix, environmentData);
            }
            else
            {
                m_texture = ContentManager.Get<Texture2D>(texture);
                BlocksManager.DrawFlatOrImageExtrusionBlock(primitivesRenderer, value, size * 1f, ref matrix, m_texture, DrawColor.HasValue ? DrawColor.Value : color, isEmissive: false, environmentData);
            }
        }

        public override int GetMaxStacking(int value)
        {
            return 99999;
        }

        public static int GetSize(int data)
        {
            return data & 7;
        }

        public static int SetSize(int data, int size)
        {
            size = MathUtils.Clamp(size, 0, 7);
            return (data & -8) | (size & 7);
        }

        public static bool GetIsWild(int data)
        {
            return (data & 8) != 0;
        }

        public static int SetIsWild(int data, bool isWild)
        {
            if (!isWild)
            {
                return data & -9;
            }

            return data | 8;
        }

        public override BlockPlacementData GetPlacementValue(SubsystemTerrain subsystemTerrain, ComponentMiner componentMiner, int value, TerrainRaycastResult raycastResult)
        {
            BlockPlacementData result = default(BlockPlacementData);
            result.CellFace = raycastResult.CellFace;
            Block block = BlocksManager.Blocks[Placementvalue];
            if (raycastResult.CellFace.Face == 4 && Terrain.ExtractData(value) == 0)
            {
                result.Value = Terrain.MakeBlockValue(block.BlockIndex, 0, SetIsWild(SetSize(0, 1), isWild: false));
            }

            return result;
        }
    }
}